
local imageio = require 'imageio'
local win32 = require 'bindings.win32'
local gdip = require 'bindings.win32.gdiplus'
local alien = require 'alien'
local yield, cowrap
    = coroutine.yield, coroutine.wrap

local boxed_ptr = alien.buffer(alien.sizeof('pointer'))

PixelFormats = {
  [gdip.PixelFormat1bppIndexed] = { code="p1", bpp=1 };
  [gdip.PixelFormat4bppIndexed] = { code="p4", bpp=4 };
  [gdip.PixelFormat8bppIndexed] = { code="p8", bpp=8 };
  [gdip.PixelFormat16bppARGB1555] = { code="a1r5g5b5", bpp=16 };
  [gdip.PixelFormat16bppGrayScale] = { code="p16", bpp=16, greyscale=true };
  [gdip.PixelFormat16bppRGB555] = { code="x1r5g5b5", bpp=16 };
  [gdip.PixelFormat16bppRGB565] = { code="r5g6b5", bpp=16 };
  [gdip.PixelFormat24bppRGB] = { code="r8g8b8", bpp=24 };
  [gdip.PixelFormat32bppARGB] = { code="a8r8g8b8", bpp=32 };
  [gdip.PixelFormat32bppPARGB] = { code="a8r8g8b8", bpp=32, premultipled_alpha=true };
  [gdip.PixelFormat32bppRGB] = { code="x8r8g8b8", bpp=32 };
  [gdip.PixelFormat48bppRGB] = { code="r16g16b16", bpp=48 };
  [gdip.PixelFormat64bppARGB] = { code="a16r16g16b16", bpp=64 };
  [gdip.PixelFormat64bppPARGB] = { code="a16r16g16b16", bpp=64, premultipled_alpha=true };
}

local function gdiplus_reader(f, path)
  local path_wide = win32.MAKE_WIDE(path)
  assert(0 == gdip.CreateBitmapFromFile(path_wide, boxed_ptr), "[gdiplus] error on CreateBitmapFromFile")
  local bitmap = boxed_ptr:get(1, 'pointer')
  local _, width = gdip.GetImageWidth(bitmap, 0)
  local _, height = gdip.GetImageHeight(bitmap, 0)
  local _, pxformat = gdip.GetImagePixelFormat(bitmap, 0)
  local pxformat_info = PixelFormats[pxformat]
  local palette = nil -- TODO
  local locked = gdip.BitmapData:new()
  gdip.BitmapLockBits(bitmap, nil, gdip.ImageModeLockRead, pxformat, locked())
  return imageio.create_reader{
    bpp = pxformat_info.bpp;
    format = pxformat_info.code;
    palette = palette;
    reader = reader;
    
    width = width;
    height = height;
    pitch = locked.Stride;
    
    getdata = cowrap(function(self)
      yield(1, height, locked.Scan0)
      return nil
    end);
    
    close = function(self)
    end;
  }
end

imageio.add_handler{
  pattern = '\137PNG\r\n\026\n';
  reader = gdiplus_reader;
}

imageio.add_handler{
  pattern = 'BM';
  reader = gdiplus_reader;
}

imageio.add_handler{
  pattern = '\255\216\255\224..JFIF%z';
  reader = gdiplus_reader;
}

imageio.add_handler{
  pattern = 'GIF8[79]a';
  reader = gdiplus_reader;
}

--[==[
local gdip = require 'bindings.win32.gdiplus'
local LOG = require 'guac.log'
local tostring
    = tostring


module (...)


logEvent = alien.callback(function(level, message)
  if (level == gdip.DebugEventLevelWarning) then
    LOG:warn("[gdiplus] " .. tostring(message))
  else
    LOG:error("[gdiplus] " .. tostring(message))
  end
end, gdip.DebugEventProc_types)

local startupInput = gdip.StartupInput:new()
startupInput.GdiplusVersion = 1
startupInput.DebugEventCallback = logEvent
startupInput.SuppressBackgroundThread = 0
startupInput.SuppressExternalCodecs = 0

local result, token = gdip.Startup(0, startupInput(), nil)
--]==]
